home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 October: Mac OS SDK / Dev.CD Oct 97 SDK2.toast / Development Kits (Disc 2) / QuickTime / Sample Code / Music Movie Header Manipulation / MMHM.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-26  |  17.3 KB  |  811 lines  |  [TEXT/CWIE]

  1.  
  2. #include <QuickTimeMusic.h>
  3. #include <stdio.h>
  4. #include <Resources.h>
  5.  
  6. void CopyString(StringPtr src,StringPtr dst,unsigned maximumLength);
  7. AtomicInstrument NewAtomicInstrument(void);
  8. AtomicInstrument NewAtomicInstrumentFromSNDHandle(Handle sndH);
  9.  
  10.  
  11.  
  12. void PrintP(StringPtr s);
  13. void PrintP(StringPtr s)
  14.     {
  15.     long x;
  16.  
  17.     x = *s++;
  18.     while(x--)
  19.         printf("%c",*s++);
  20.     }
  21.  
  22.  
  23. OSErr GetTrackType(Track tr,OSType *trackTypeOut);
  24. OSErr GetTrackType(Track tr,OSType *trackTypeOut)
  25.     {
  26.     OSErr err = noErr;
  27.     Media me;
  28.     OSType trackType = 0;
  29.  
  30.     me = GetTrackMedia(tr);
  31.     if(err = GetMoviesError())
  32.         goto goHome;
  33.  
  34.     GetMediaHandlerDescription(me, &trackType, nil, nil);
  35.     if(err = GetMoviesError())
  36.         goto goHome;
  37.  
  38. goHome:
  39.     if(err)
  40.         trackType = 0;
  41.     if(trackTypeOut)
  42.         *trackTypeOut = trackType;
  43.     return err;
  44.     }
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51. #define kSampleLength 256
  52.  
  53.  
  54. AtomicInstrument NewAtomicInstrument(void)
  55.     {
  56.     ComponentResult result;
  57.     AtomicInstrument ai = 0;
  58.     unsigned char *x = 0;
  59.     long i;
  60.     ToneDescription td;
  61.     double a,b;
  62.     InstSampleDescRec isd;
  63.  
  64.     x = (unsigned char *)NewPtrClear(kSampleLength);
  65.     if(!x)
  66.         goto goHome;
  67.  
  68.     result = QTNewAtomContainer(&ai);
  69.     if(result)
  70.         goto goHome;
  71.  
  72.     td.synthesizerType = kSoftSynthComponentSubType;
  73.     td.synthesizerName[0] = 0;
  74.     CopyString("\pSawtooth",td.instrumentName,31);
  75.     td.instrumentNumber = 1;
  76.     td.gmNumber = 0;
  77.  
  78.         {
  79.         QTAtom keyrangeInfoAtom;
  80.         result = QTInsertChild( ai, 0, kaiToneDescType, 1, 1,
  81.                 sizeof(ToneDescription),&td,nil );
  82.         if(result)
  83.             goto goHome;
  84.  
  85.         result = QTInsertChild( ai, 0, kaiKeyRangeInfoType, 1, 1, 0, nil, &keyrangeInfoAtom );
  86.  
  87.         isd.dataFormat = 'raw ';
  88.         isd.numChannels = 1;
  89.         isd.sampleSize = 8;
  90.         isd.sampleRate = ((long)0x6e00)<<16;
  91.         isd.sampleDataID = 23;
  92.         isd.offset = 0;
  93.         isd.numSamples = kSampleLength;
  94.  
  95.         isd.loopType = 0;
  96.         isd.loopStart = 0;
  97.         isd.loopEnd = kSampleLength;
  98.  
  99.         isd.pitchNormal = 57;
  100.         isd.pitchLow = 0;
  101.         isd.pitchHigh = 128;
  102.  
  103.         result = QTInsertChild( ai, keyrangeInfoAtom, kaiSampleDescType, 1, 1,
  104.                 sizeof(InstSampleDescRec), &isd, nil );
  105.         }
  106.  
  107. #define kaiSampleNameType 'snam'
  108.  
  109.     for(i = 0; i < kSampleLength; i++)
  110.         x[i] = i;
  111.  
  112.         {
  113.         QTAtom sminA = 0;
  114.         Str255 sampleName;
  115.  
  116.         result = QTInsertChild(ai,0,kaiSampleInfoType, 23, 0, 0, nil, &sminA);
  117.  
  118.         result = QTInsertChild(ai,sminA, kaiSampleDataType, 23, 0,
  119.                 kSampleLength, x, nil);
  120.  
  121.         CopyString("\pQTMA Example Waveform",sampleName,255);
  122.         result = QTInsertChild(ai,sminA, kaiSampleNameType, 1, 0,
  123.             sampleName[0],sampleName+1,nil);
  124.         }
  125.  
  126. goHome:
  127.     if(x)
  128.         DisposePtr((Ptr)x);
  129.     x = 0;
  130.  
  131.     if(result)
  132.         {
  133.         if(ai)
  134.             QTDisposeAtomContainer(ai);
  135.         ai = 0;
  136.         }
  137.     return ai;
  138.     }
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147.  
  148.  
  149.  
  150.  
  151.  
  152.  
  153.  
  154. typedef struct
  155.     {
  156.     long partType;            // subtype of the general event, kGeneralEventAtomicInstrument or kGeneralEventNoteRequest
  157.     long partOffset;        // number of *longwords* into the sample description for the part
  158.     long partEventLength;
  159.     long partNumber;
  160.     } PartStuff;
  161.  
  162. #define kMaxPartCount 100    // a random number, but we're putting this junk on the stack after all
  163. #define kEndMarker 0x60000000
  164.  
  165.  
  166. OSErr PullPartList(MusicDescriptionHandle descH,long *partCountOut,PartStuff *partStuff);
  167. OSErr PullPartList(MusicDescriptionHandle descH,long *partCountOut,PartStuff *partStuff)
  168. /*
  169.  * walk the sample description, and fill in the partcount & partstuff list
  170.  *
  171.  * Each routine calls this one itself, just to keep us honest. Every time the partlist
  172.  * is printed, the PrintPartList routine calls us. Each time we replace one of the
  173.  * instruments, we're called. Avoids all problems with keeping the data in synch with itself.
  174.  */
  175.     {
  176.     OSErr err = noErr;
  177.     long partCount;
  178.     PartStuff *psW;
  179.     unsigned long *start,*end,*w;
  180.     unsigned long x,y;
  181.     long eventLength;
  182.     long eventType;
  183.     long eventSubtype;
  184.     long i;
  185.     MusicDescriptionPtr descP;
  186.  
  187.     descP = *descH;
  188.  
  189.     start = descP->headerData;
  190.     end = (unsigned long *)( ((char *)descP) + descP->descSize);
  191.  
  192.     // • Make list of note request and atomic instrument events
  193.     w = start;
  194.     partCount = 0;
  195.     psW = partStuff;
  196.     while(w < end)
  197.         {
  198.         x = *w;
  199.         qtma_EventLengthForward(w,eventLength);
  200.         eventType = qtma_EventType(x);
  201.         if(eventType == kGeneralEventType)
  202.             {
  203.             y = *(w + eventLength - 1);
  204.             eventSubtype = qtma_GeneralSubtype(x,y);
  205.             if(eventSubtype == kGeneralEventAtomicInstrument
  206.                     || eventSubtype == kGeneralEventNoteRequest)
  207.                 {
  208.                 psW->partType = eventSubtype;
  209.                 psW->partOffset = w - start;
  210.                 psW->partEventLength = eventLength;
  211.                 psW->partNumber = qtma_XPart(x,y);
  212.                 partCount++;
  213.                 psW++;
  214.                 }
  215.             }
  216.         else if(x == kEndMarker)
  217.             w = end;
  218.  
  219.         w += eventLength;
  220.         }
  221.  
  222.     *partCountOut = partCount;
  223.  
  224. goHome:
  225.     return err;
  226.     }
  227.  
  228.  
  229. void CopyString(StringPtr src,StringPtr dst,unsigned maximumLength)
  230. /*
  231.  * Copy from src to dst, where the string length is no more
  232.  * than maximumLength. Affects maximumLength+1 bytes of course.
  233.  */
  234.     {
  235.     long x;
  236.  
  237.     x = maximumLength;
  238.     while(x >= 0)
  239.         dst[x--] = 0;
  240.  
  241.     if(maximumLength > src[0])
  242.         maximumLength = src[0];
  243.  
  244.     *dst++ = maximumLength;
  245.     *src++;
  246.  
  247.     while(maximumLength--)
  248.         *dst++ = *src++;
  249.     }
  250.  
  251.  
  252. OSErr GetAtomicInstrumentName(AtomicInstrumentPtr aiP,Str255 instName);
  253. OSErr GetAtomicInstrumentName(AtomicInstrumentPtr aiP,Str255 instName)
  254.     {
  255.     AtomicInstrument ai;
  256.     QTAtom toneA;
  257.     OSErr err = noErr;
  258.     ToneDescription td;
  259.  
  260.     instName[0] = 0;
  261.  
  262.     ai = &aiP;        // fake
  263.     toneA = QTFindChildByIndex(ai, nil, kaiToneDescType, 1, nil);
  264.  
  265.     err = QTCopyAtomDataToPtr(ai, toneA, false, sizeof(ToneDescription), &td, nil);
  266.     if(err)
  267.         goto goHome;
  268.  
  269.     CopyString(td.instrumentName,instName,255);
  270.  
  271. goHome:
  272.     return err;
  273.     }
  274.  
  275. OSErr PrintPartList(MusicDescriptionHandle descH);
  276. OSErr PrintPartList(MusicDescriptionHandle descH)
  277.     {
  278.     OSErr err = noErr;
  279.     MusicDescriptionPtr descP;
  280.     long partCount;
  281.     PartStuff partStuff[kMaxPartCount],*psW;
  282.     long i;
  283.  
  284.     PullPartList(descH,&partCount,partStuff);
  285.  
  286.     // • Print the names of the instruments
  287.     printf("%ld parts in music track\n",partCount);
  288.     for(i = 1; i <= partCount; i++)
  289.         {
  290.         psW = partStuff + i - 1;
  291.         printf("part %ld: ",i);
  292.         if(psW->partType == kGeneralEventAtomicInstrument)
  293.             {
  294.             Str255 instName;
  295.  
  296.             err = GetAtomicInstrumentName((AtomicInstrumentPtr) ((**descH).headerData + psW->partOffset + 1), instName);
  297.             if(err)
  298.                 goto goHome;
  299.             PrintP(instName);
  300.             printf(" (atomic)");
  301.             }
  302.         else
  303.             PrintP(((NoteRequest *)((**descH).headerData + psW->partOffset + 1))->tone.instrumentName);
  304.         printf("\n");
  305.         }
  306.     printf("\n");
  307. goHome:
  308.     return err;
  309.     }
  310.  
  311. OSErr ReplaceInstrument(MusicDescriptionHandle descH,long partIndex,AtomicInstrument ai,NoteRequest *nr);
  312. OSErr ReplaceInstrument(MusicDescriptionHandle descH,long partIndex,AtomicInstrument ai,NoteRequest *nr)
  313. /*
  314.  * Replace a part with either an atomic instrument, or a noterequest (whichever is nonzero)
  315.  */
  316.     {
  317.     OSErr err = noErr;
  318.     long partCount;
  319.     PartStuff partStuff[kMaxPartCount],*psW;
  320.     long oldEventLength,newEventLength;        // in longs
  321.     long oldDescHLength,newDescHLength;        // in bytes
  322.     long eventShift;                        // in bytes
  323.     unsigned long eventHead,eventTail,*eventBody;
  324.     long oldPartEventByteOffset;
  325.     char *base,*end;
  326.  
  327.     err = PullPartList(descH,&partCount,partStuff);
  328.     if(err)
  329.         goto goHome;
  330.  
  331.     if(partIndex > partCount || partIndex <= 0)
  332.         {
  333.         err = -1;
  334.         goto goHome;
  335.         }
  336.  
  337.     psW = partStuff + partIndex - 1;
  338.  
  339.     oldDescHLength = GetHandleSize((Handle)descH);
  340.     oldEventLength = psW->partEventLength;
  341.     oldPartEventByteOffset = ((char *)((**descH).headerData + psW->partOffset)) - ((char *)(*descH));
  342.  
  343.     if(ai)
  344.         {
  345.         newEventLength = (GetHandleSize(ai) + sizeof(long) - 1) / sizeof(long) + 2;
  346.         qtma_StuffGeneralEvent(eventHead,eventTail,psW->partNumber,kGeneralEventAtomicInstrument,newEventLength);
  347.         }
  348.     else if(nr)
  349.         {
  350.         newEventLength = (sizeof(NoteRequest) + sizeof(long) - 1) / sizeof(long) + 2;
  351.         qtma_StuffGeneralEvent(eventHead,eventTail,psW->partNumber,kGeneralEventNoteRequest,newEventLength);
  352.         }
  353.     else
  354.         {
  355.         err = -2;
  356.         goto goHome;
  357.         }
  358.  
  359.     eventShift = sizeof(long) * (newEventLength - oldEventLength);
  360.  
  361.     newDescHLength = oldDescHLength + eventShift;
  362.  
  363.  
  364.     if(eventShift > 0)
  365.         {
  366.         SetHandleSize((Handle)descH,newDescHLength);
  367.         base = (char *)(*descH);
  368.         end = base + oldDescHLength;
  369.         BlockMove(base + oldPartEventByteOffset,
  370.                 base + oldPartEventByteOffset + eventShift,
  371.                 end - (base + oldPartEventByteOffset));
  372.         }
  373.     else
  374.         {
  375.         eventShift = -eventShift;
  376.         base = (char *)(*descH);
  377.         end = base + oldDescHLength;
  378.         BlockMove(base + oldPartEventByteOffset + eventShift,
  379.                 base + oldPartEventByteOffset,
  380.                 end - (base + oldPartEventByteOffset + eventShift));
  381.         SetHandleSize((Handle)descH,newDescHLength);
  382.         }    
  383.  
  384.  
  385.     (**descH).descSize = newDescHLength;
  386.     (**descH).headerData[psW->partOffset] = eventHead;
  387.     (**descH).headerData[psW->partOffset + newEventLength - 1] = eventTail;
  388.  
  389.     if(ai)
  390.         BlockMove(*ai,(**descH).headerData + psW->partOffset + 1,sizeof(long) * (newEventLength - 2));
  391.     else
  392.         BlockMove(nr,(**descH).headerData + psW->partOffset + 1,sizeof(long) * (newEventLength - 2));
  393.  
  394. goHome:
  395.     return err;
  396.     }
  397.  
  398.  
  399. OSErr MuckWithMusicTrackSampleDescription(Movie mo,Track tr);
  400. OSErr MuckWithMusicTrackSampleDescription(Movie mo,Track tr)
  401.     {
  402.     OSErr err = noErr;
  403.     Media me;
  404.     MusicDescriptionHandle descH;
  405.     long i;
  406.     long partCount;
  407.     PartStuff partStuff[kMaxPartCount];
  408.     Handle sndH = 0;
  409.  
  410.     sndH = GetResource('snd ',129);
  411.  
  412.     me = GetTrackMedia(tr);
  413.     if(err = GetMoviesError())
  414.         goto goHome;
  415.  
  416.     descH = (MusicDescriptionHandle)NewHandle(0);
  417.  
  418.     GetMediaSampleDescription(me, 1, (SampleDescriptionHandle)descH);
  419.     if(err = GetMoviesError())
  420.         goto goHome;
  421.  
  422.     // • Print the names of the instruments
  423.     PrintPartList(descH);
  424.  
  425.     // • Make list of note request and atomic instrument events
  426.     err = PullPartList(descH,&partCount,partStuff);
  427.     if(err)
  428.         goto goHome;
  429.  
  430.     // • Replace an instrument
  431.         {
  432.         AtomicInstrument ai = 0;
  433.  
  434.         // replace all but the last instrument with this atomic thingie
  435.         ai = NewAtomicInstrumentFromSNDHandle(sndH);
  436.         //ai = NewAtomicInstrument();
  437.         for(i = 1; i <= partCount - 1; i++)
  438.             err = ReplaceInstrument(descH,i,ai,nil);
  439.  
  440.         // replace the 3rd instrument, if there is one, with a GM instrument
  441.         if(partCount >= 3)
  442.             {
  443.             NoteAllocator na;
  444.             NoteRequest nr;
  445.  
  446.             nr.info.polyphony = 2;
  447.             nr.info.typicalPolyphony = 0x00010000;
  448.  
  449.             na = OpenDefaultComponent(kNoteAllocatorComponentType,0);
  450.             if(!na)
  451.                 {
  452.                 err = -1;
  453.                 goto goHome;
  454.                 }
  455.             NAStuffToneDescription(na,40,&nr.tone);
  456.             CloseComponent(na);
  457.             err = ReplaceInstrument(descH,3,nil,&nr);
  458.             }
  459.  
  460.         // Set the new sample description
  461.         err = SetMediaSampleDescription(me,1,(SampleDescriptionHandle)descH);
  462.         PrintPartList(descH);
  463.  
  464.         printf("Playing movie now; click to stop.\n\n");
  465.  
  466.         StartMovie(mo);
  467.         while(!Button())
  468.             MoviesTask(0,1000);
  469.         while(StillDown())
  470.             MoviesTask(0,1000);
  471.         StopMovie(mo);
  472.         }
  473.  
  474. goHome:
  475.     return err;
  476.     }
  477.  
  478. void main(void);
  479. void main(void)
  480.     {
  481.     StandardFileReply sfr;
  482.     OSType fileType;
  483.     Movie mo;
  484.     Track tr,musicTrack;
  485.     OSType trackType;
  486.     short resRefNum;
  487.     OSErr err = 0;
  488.     long i,trackCount,musicTrackIndex;
  489.     Boolean enteredMovies = false;
  490.  
  491.     // • Print something so SIOUX will fire up the toolbox and stuff
  492.     printf("Music Movie Header Manipulation\n");
  493.     printf("September 1996, dvb, Apple Computer\n\n");
  494.  
  495.     // • Open a file, or go home
  496.     fileType = MovieFileType;
  497.     StandardGetFilePreview(nil, 1, &fileType, &sfr);
  498.     if(!sfr.sfGood)
  499.         goto goHome;
  500.  
  501.     EnterMovies();
  502.     enteredMovies = true;
  503.  
  504.     resRefNum = 0;
  505.     err = OpenMovieFile(&sfr.sfFile, &resRefNum, fsRdPerm);
  506.     if(err)
  507.         goto goHome;
  508.  
  509.     mo = 0;
  510.     err = NewMovieFromFile(&mo, resRefNum, nil, nil, 0, nil);
  511.     if(err)
  512.         goto goHome;
  513.  
  514.     // • Find the first music track, and disable everything else
  515.     trackCount = GetMovieTrackCount(mo);
  516.     if(err = GetMoviesError())
  517.         goto goHome;
  518.  
  519.     musicTrackIndex = 0;
  520.     musicTrack = 0;
  521.  
  522.     for(i = 1; i <= trackCount; i++)
  523.         {
  524.         tr = GetMovieIndTrack(mo, i);
  525.         if(err = GetMoviesError())
  526.             goto goHome;
  527.  
  528.         err = GetTrackType(tr,&trackType);
  529.         if(err)
  530.             goto goHome;
  531.  
  532.         if(!musicTrackIndex && trackType == MusicMediaType)
  533.             {
  534.             musicTrackIndex = i;
  535.             musicTrack = tr;
  536.             SetTrackEnabled(tr, true);
  537.             if(err = GetMoviesError())
  538.                 goto goHome;
  539.             }
  540.         else
  541.             {
  542.             SetTrackEnabled(tr, false);
  543.             if(err = GetMoviesError())
  544.                 goto goHome;
  545.             }
  546.         }
  547.  
  548.     if(!musicTrack)
  549.         {
  550.         printf("No music tracks in movie.\n");
  551.         goto goHome;
  552.         }
  553.  
  554.     err = MuckWithMusicTrackSampleDescription(mo,tr);
  555.  
  556. goHome:
  557.     if(err)
  558.         printf("error: %d\n",err);
  559.  
  560.     if(resRefNum)
  561.         {
  562.         if(mo)
  563.             DisposeMovie(mo);
  564.         CloseMovieFile(resRefNum);
  565.         }
  566.     if(enteredMovies)
  567.         ExitMovies();
  568.  
  569.     printf("All done with the Music Media Header Manipulation.\n\n");
  570.     }
  571.  
  572.  
  573.  
  574. typedef struct
  575.     {
  576.     union
  577.         {
  578.         SoundHeader s;
  579.         CmpSoundHeader c;
  580.         ExtSoundHeader e;
  581.         } u;
  582.     } CommonSoundHeader;
  583.  
  584.  
  585. OSErr ParseSnd(Handle sndH, InstSampleDescRec *sd, unsigned long *dataOffsetResult, unsigned long *dataSizeResult);
  586. OSErr ParseSnd(Handle sndH, InstSampleDescRec *sd, unsigned long *dataOffsetResult, unsigned long *dataSizeResult)
  587. /* Given an 'SND ' in a handle, fill out a QTMA InstSampleDescRec, and return the
  588.  * offset in bytes into the handle of the audio data, and the size of the audio data, in bytes.
  589.  */
  590.     {
  591.     CommonSoundHeader    *sh;
  592.     long            dataOffset;
  593.     OSErr            err;
  594.     long sizeMultiplier = 1;
  595.  
  596.         {
  597.         char *w;
  598.         long i;
  599.  
  600.         w = (char *)sd;
  601.         for(i = 0; i < sizeof(InstSampleDescRec); i++)
  602.             *w++ = 0;
  603.         }
  604.  
  605.     sd->pitchNormal = 60;
  606.     sd->pitchLow = 0;
  607.     sd->pitchHigh = 127;
  608.  
  609.     err = GetSoundHeaderOffset((SndListHandle) sndH, &dataOffset);
  610.     if (err != noErr)
  611.         return (err);
  612.  
  613.     sh = (CommonSoundHeader *) (*sndH + dataOffset);
  614.  
  615.     switch (sh->u.s.encode)
  616.     {
  617.         case stdSH:
  618.             sd->numSamples = sh->u.s.length;
  619.             sd->sampleRate = sh->u.s.sampleRate;
  620.             sd->sampleSize = 8;
  621.             sd->numChannels = 1;
  622.             sd->loopStart = sh->u.s.loopStart;
  623.             sd->loopEnd = sh->u.s.loopEnd;
  624.             sd->pitchNormal = sh->u.s.baseFrequency;
  625.             dataOffset += ((char *)&sh->u.s.sampleArea) - ((char *)&sh->u);
  626.             sd->dataFormat = 'raw ';
  627.             break;
  628.  
  629.         case extSH:
  630.             sd->numSamples = sh->u.e.numFrames;
  631.             sd->sampleRate = sh->u.e.sampleRate;
  632.             sd->sampleSize = sh->u.e.sampleSize;
  633.             sd->numChannels = sh->u.e.numChannels;
  634.             sd->loopStart = sh->u.e.loopStart;
  635.             sd->loopEnd = sh->u.e.loopEnd;
  636.             sd->pitchNormal = sh->u.e.baseFrequency;
  637.             dataOffset += ((char *)&sh->u.e.sampleArea) - ((char *)&sh->u);
  638.             if (sh->u.e.sampleSize == 8)
  639.                 sd->dataFormat = 'raw ';
  640.             else
  641.                 sd->dataFormat = 'twos';
  642.             break;
  643.  
  644.         case cmpSH:
  645.             sd->numSamples = sh->u.c.numFrames;
  646.             sd->sampleRate = sh->u.c.sampleRate;
  647.             sd->sampleSize = sh->u.c.sampleSize;
  648.             sd->numChannels = sh->u.c.numChannels;
  649.             sd->loopStart = sh->u.c.loopStart;
  650.             sd->loopEnd = sh->u.c.loopEnd;
  651.             sd->pitchNormal = sh->u.c.baseFrequency;
  652.             dataOffset += ((char *)&sh->u.c.sampleArea) - ((char *)&sh->u);
  653.             switch ((short) sh->u.c.compressionID)
  654.             {
  655.                 case fixedCompression:
  656.                     sd->dataFormat = sh->u.c.format;
  657.                     break;
  658.                 case notCompressed:
  659.                     if (sh->u.c.sampleSize == 8)
  660.                         sd->dataFormat = 'raw ';
  661.                     else
  662.                         sd->dataFormat = 'twos';
  663.                     break;
  664.                 case threeToOne:
  665.                     sd->dataFormat = 'MAC3';
  666.                     sizeMultiplier = 3;
  667.                     break;
  668.                 case sixToOne:
  669.                     sd->dataFormat = 'MAC6';
  670.                     sizeMultiplier = 6;
  671.                     break;
  672.             }
  673.             break;
  674.     }
  675.  
  676.     if(sd->loopEnd - sd->loopStart < 20)
  677.         sd->loopEnd = sd->loopStart = 0;
  678.  
  679.  
  680.     if(dataOffsetResult)
  681.         *dataOffsetResult = dataOffset;
  682.  
  683.     sizeMultiplier *= sd->numChannels;
  684.     if(sd->sampleSize == 16)
  685.         sizeMultiplier *= 2;
  686.     if(dataSizeResult)
  687.         *dataSizeResult = sd->numSamples * sizeMultiplier;
  688.     return (noErr);
  689. }
  690.  
  691.  
  692.  
  693.  
  694.  
  695.  
  696.  
  697.  
  698.  
  699.  
  700. AtomicInstrument NewAtomicInstrumentFromSNDHandle(Handle sndH)
  701.     {
  702.     ComponentResult result;
  703.     AtomicInstrument ai = 0;
  704.     unsigned char *x = 0;
  705.     long i;
  706.     ToneDescription td;
  707.     double a,b;
  708.     InstSampleDescRec isd;
  709.     unsigned long sndAudioOffset,sndAudioLength;
  710.  
  711.     x = (unsigned char *)NewPtrClear(kSampleLength);
  712.     if(!x)
  713.         goto goHome;
  714.  
  715.     result = QTNewAtomContainer(&ai);
  716.     if(result)
  717.         goto goHome;
  718.  
  719.     td.synthesizerType = kSoftSynthComponentSubType;
  720.     td.synthesizerName[0] = 0;
  721.     if(sndH)
  722.         CopyString("\pSnd Resource",td.instrumentName,31);
  723.     else
  724.         CopyString("\pSawtooth",td.instrumentName,31);
  725.     td.instrumentNumber = 1;
  726.     td.gmNumber = 0;
  727.  
  728.         {
  729.         QTAtom keyrangeInfoAtom;
  730.         result = QTInsertChild( ai, 0, kaiToneDescType, 1, 1,
  731.                 sizeof(ToneDescription),&td,nil );
  732.         if(result)
  733.             goto goHome;
  734.  
  735.         result = QTInsertChild( ai, 0, kaiKeyRangeInfoType, 1, 1, 0, nil, &keyrangeInfoAtom );
  736.  
  737. Debugger();
  738.         if(sndH)
  739.             {
  740.             ParseSnd(sndH, &isd, &sndAudioOffset,&sndAudioLength);
  741.             isd.sampleDataID = 23;
  742.             }
  743.         else
  744.             {
  745.             isd.dataFormat = 'raw ';
  746.             isd.numChannels = 1;
  747.             isd.sampleSize = 8;
  748.             isd.sampleRate = ((long)0x6e00)<<16;
  749.             isd.sampleDataID = 23;
  750.             isd.offset = 0;
  751.             isd.numSamples = kSampleLength;
  752.  
  753.             isd.loopType = 0;
  754.             isd.loopStart = 0;
  755.             isd.loopEnd = kSampleLength;
  756.  
  757.             isd.pitchNormal = 57;
  758.             isd.pitchLow = 0;
  759.             isd.pitchHigh = 128;
  760.             }
  761.  
  762.         result = QTInsertChild( ai, keyrangeInfoAtom, kaiSampleDescType, 1, 1,
  763.                 sizeof(InstSampleDescRec), &isd, nil );
  764.         }
  765.  
  766. #define kaiSampleNameType 'snam'
  767.  
  768.     for(i = 0; i < kSampleLength; i++)
  769.         x[i] = i;
  770.  
  771.         {
  772.         QTAtom sminA = 0;
  773.         Str255 sampleName;
  774.  
  775.         result = QTInsertChild(ai,0,kaiSampleInfoType, 23, 0, 0, nil, &sminA);
  776.  
  777.         if(sndH)
  778.             {
  779.             HLock(sndH);
  780.             result = QTInsertChild(ai,sminA, kaiSampleDataType, 23, 0,
  781.                     sndAudioLength, (*sndH) + sndAudioOffset, nil);
  782.             HUnlock(sndH);
  783.             }
  784.         else
  785.             result = QTInsertChild(ai,sminA, kaiSampleDataType, 23, 0,
  786.                     kSampleLength, x, nil);
  787.  
  788.         if(sndH)
  789.             CopyString("\pImported SND Waveform",sampleName,255);
  790.         else
  791.             CopyString("\pQTMA Example Waveform",sampleName,255);
  792.         result = QTInsertChild(ai,sminA, kaiSampleNameType, 1, 0,
  793.                 sampleName[0],sampleName+1,nil);
  794.         }
  795.  
  796. goHome:
  797.     if(x)
  798.         DisposePtr((Ptr)x);
  799.     x = 0;
  800.  
  801.     if(result)
  802.         {
  803.         if(ai)
  804.             QTDisposeAtomContainer(ai);
  805.         ai = 0;
  806.         }
  807.     return ai;
  808.     }
  809.  
  810.  
  811.